package com.gzc.just.play.last.war.centralserver.battle;

import com.gzc.just.play.last.war.centralserver.config.CentralServerConfig;
import com.gzc.just.play.last.war.centralserver.match.BattleMatchManager;
import com.gzc.just.play.last.war.centralserver.service.UserStatusService;
import com.gzc.just.play.last.war.centralserver.battle.model.Battle;
import com.gzc.just.play.last.war.centralserver.battle.model.BattleRoom;
import com.gzc.just.play.last.war.centralserver.battle.model.BattleStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

@Component("central-battleManager")
public class BattleManager {
    private static final Logger logger = LoggerFactory.getLogger(BattleManager.class);
    
    @Autowired(required = false)
    private CentralServerConfig config;
    
    @Autowired(required = false)
    private UserStatusService userService;
    
    @Autowired(required = false)
    @org.springframework.context.annotation.Lazy
    private BattleMatchManager matchManager;
    
    private final ConcurrentHashMap<Long, Battle> battleMap = new ConcurrentHashMap<>();
    
    private final ConcurrentHashMap<Long, BattleRoom> battleRoomMap = new ConcurrentHashMap<>();
    
    private final ConcurrentHashMap<Long, Long> userToBattleId = new ConcurrentHashMap<>();
    
    private final ConcurrentHashMap<Long, Long> userToRoomId = new ConcurrentHashMap<>();
    
    private final AtomicLong battleIdGenerator = new AtomicLong(1000);
    
    private final AtomicLong roomIdGenerator = new AtomicLong(1000);
    
    @PostConstruct
    public void init() {
        logger.info("BattleManager initialized");
    }
    
    @PreDestroy
    public void destroy() {
        for (Battle battle : battleMap.values()) {
            destroyBattle(battle.getBattleId());
        }
        
        for (BattleRoom room : battleRoomMap.values()) {
            destroyRoom(room.getRoomId());
        }
        
        logger.info("BattleManager destroyed");
    }
    
    public CompletableFuture<Battle> createBattle(long creatorId, String battleName, int mapId, int maxPlayers) {
        long battleId = battleIdGenerator.incrementAndGet();
        
        logger.info("Creating battle: creatorId={}, battleName={}, mapId={}, maxPlayers={}, battleId={}", 
                   creatorId, battleName, mapId, maxPlayers, battleId);
        
        Battle battle = new Battle();
        battle.setBattleId(battleId);
        battle.setCreatorId(creatorId);
        battle.setBattleName(battleName);
        battle.setMapId(mapId);
        battle.setMaxPlayers(maxPlayers);
        battle.setStatus(BattleStatus.WAITING);
        battle.setCreateTime(System.currentTimeMillis());
        
        battle.addPlayer(creatorId);
        
        battleMap.put(battleId, battle);
        userToBattleId.put(creatorId, battleId);
        
        notifySceneServerCreateBattle(battle);
        
        return CompletableFuture.completedFuture(battle);
    }
    
    public Battle getBattle(long battleId) {
        return battleMap.get(battleId);
    }
    
    public boolean addPlayerToBattle(long battleId, long playerId) {
        Battle battle = battleMap.get(battleId);
        if (battle == null) {
            logger.warn("Battle {} not found", battleId);
            return false;
        }
        
        if (battle.getPlayerCount() >= battle.getMaxPlayers()) {
            logger.warn("Battle {} is full", battleId);
            return false;
        }
        
        battle.addPlayer(playerId);
        userToBattleId.put(playerId, battleId);
        
        logger.debug("Player {} joined battle {}", playerId, battleId);
        notifySceneServerPlayerJoined(battleId, playerId);
        
        return true;
    }
    
    public boolean removePlayerFromBattle(long battleId, long playerId) {
        Battle battle = battleMap.get(battleId);
        if (battle == null) {
            logger.warn("Battle {} not found", battleId);
            return false;
        }
        
        battle.removePlayer(playerId);
        userToBattleId.remove(playerId);
        
        logger.debug("Player {} left battle {}", playerId, battleId);
        notifySceneServerPlayerLeft(battleId, playerId);
        
        if (battle.getPlayerCount() == 0) {
            destroyBattle(battleId);
        }
        
        return true;
    }
    
    public boolean startBattle(long battleId) {
        Battle battle = battleMap.get(battleId);
        if (battle == null) {
            logger.warn("Battle {} not found", battleId);
            return false;
        }
        
        if (battle.getStatus() != BattleStatus.WAITING) {
            logger.warn("Battle {} status is {}, cannot start", battleId, battle.getStatus());
            return false;
        }
        
        battle.setStatus(BattleStatus.STARTED);
        logger.info("Battle {} started", battleId);
        notifySceneServerStartBattle(battleId);
        
        return true;
    }
    
    public boolean finishBattle(long battleId) {
        Battle battle = battleMap.get(battleId);
        if (battle == null) {
            logger.warn("Battle {} not found", battleId);
            return false;
        }
        
        if (battle.getStatus() == BattleStatus.FINISHED) {
            logger.debug("Battle {} already finished", battleId);
            return false;
        }
        
        battle.setStatus(BattleStatus.FINISHED);
        battle.setFinishTime(System.currentTimeMillis());
        logger.info("Battle {} finished", battleId);
        notifySceneServerFinishBattle(battleId);
        
        return true;
    }
    
    public void destroyBattle(long battleId) {
        Battle battle = battleMap.remove(battleId);
        if (battle != null) {
            for (Long playerId : battle.getPlayers()) {
                userToBattleId.remove(playerId);
            }
            logger.info("Battle {} destroyed", battleId);
            notifySceneServerDestroyBattle(battleId);
        }
    }
    
    public BattleRoom createRoom(long creatorId, String roomName) {
        long roomId = roomIdGenerator.incrementAndGet();
        
        BattleRoom room = new BattleRoom();
        room.setRoomId(roomId);
        room.setCreatorId(creatorId);
        room.setRoomName(roomName);
        room.setCreateTime(System.currentTimeMillis());
        
        battleRoomMap.put(roomId, room);
        userToRoomId.put(creatorId, roomId);
        
        logger.info("Room {} created by player {}", roomId, creatorId);
        return room;
    }
    
    public BattleRoom createBattleRoom(List<Long> playerIds, String roomName, int mapId) {
        long roomId = roomIdGenerator.incrementAndGet();
        
        BattleRoom room = new BattleRoom();
        room.setRoomId(roomId);
        if (!playerIds.isEmpty()) {
            room.setCreatorId(playerIds.get(0));
        }
        room.setRoomName(roomName);
        room.setCreateTime(System.currentTimeMillis());
        room.setMaxPlayers(playerIds.size());
        room.setCurrentPlayers(playerIds.size());
        
        battleRoomMap.put(roomId, room);
        for (Long playerId : playerIds) {
            userToRoomId.put(playerId, roomId);
        }
        
        logger.info("BattleRoom {} created with {} players, mapId: {}", roomId, playerIds.size(), mapId);
        return room;
    }
    
    public BattleRoom getRoom(long roomId) {
        return battleRoomMap.get(roomId);
    }
    
    public void destroyRoom(long roomId) {
        BattleRoom room = battleRoomMap.remove(roomId);
        if (room != null) {
            userToRoomId.remove(room.getCreatorId());
            logger.info("Room {} destroyed", roomId);
        }
    }
    
    public int getBattleCount() {
        return battleMap.size();
    }
    
    public int getActivePlayerCount() {
        int count = 0;
        for (Battle battle : battleMap.values()) {
            count += battle.getPlayerCount();
        }
        return count;
    }
    
    @Scheduled(fixedDelay = 60000)
    public void cleanupExpiredBattles() {
        long currentTime = System.currentTimeMillis();
        long timeout = 600000;
        List<Long> expiredBattles = new ArrayList<>();
        
        for (Battle battle : battleMap.values()) {
            long battleAge = currentTime - battle.getCreateTime();
            if (battleAge > timeout && battle.getStatus() == BattleStatus.WAITING) {
                expiredBattles.add(battle.getBattleId());
            }
        }
        
        for (Long battleId : expiredBattles) {
            logger.info("Cleaning up expired battle {}", battleId);
            destroyBattle(battleId);
        }
    }
    
    private void notifySceneServerCreateBattle(Battle battle) {
        logger.debug("Notifying SceneServer to create battle {}", battle.getBattleId());
    }
    
    private void notifySceneServerPlayerJoined(long battleId, long userId) {
        logger.debug("Notifying SceneServer player {} joined battle {}", userId, battleId);
    }
    
    private void notifySceneServerPlayerLeft(long battleId, long userId) {
        logger.debug("Notifying SceneServer player {} left battle {}", userId, battleId);
    }
    
    private void notifySceneServerStartBattle(long battleId) {
        logger.debug("Notifying SceneServer battle {} started", battleId);
    }
    
    private void notifySceneServerFinishBattle(long battleId) {
        logger.debug("Notifying SceneServer battle {} finished", battleId);
    }
    
    private void notifySceneServerDestroyBattle(long battleId) {
        logger.debug("Notifying SceneServer battle {} destroyed", battleId);
    }
    
    public enum BattleResult {
        WIN,
        LOSE,
        DRAW,
        TIMEOUT
    }
}
